/*
 * Author: vyouzhi <vyouzhi@163.com>
 * http://www.xda.cn
 *
 * File: status_lib.c
 * Create Date: 2012-02-01 15:37:01
 *
 */

#include <string.h>

#include "status_lib.h"
#include "mysql_lib.h"


void status_init_all(void){
    pthread_mutex_init(&sta_lock, NULL);
    
    status_object_head = NULL;

}

STA_VALUE *status_value_init(void){
    STA_VALUE *sta_value_head;
    
    sta_value_head = (STA_VALUE *)calloc(1, sizeof(STA_VALUE));
    sta_value_head->sta_base_link = NULL;
    sta_value_head->sta_explain_link = NULL;
    
    return sta_value_head;
}

void Get_FieldName(void){
    FieldName *field_name, *field_head;
    unsigned int i;
    char status_field[5][20]={"sql","md5_sql","query_took","error_num","hits"};

    field_head = NULL;
    for(i=0; i < 5; i++){
        field_name = (FieldName *)calloc(1, sizeof(FieldName));
        field_name->fn = strdup(status_field[i]);
        field_name->next = field_head;
        field_head = field_name;
    }
   
    status_fn_head = field_head;
}

void FieldName_free(FieldName *fn_head){
    FieldName *fn_run, *fn_tmp;

    fn_run = fn_head;
    while(fn_run){
        fn_tmp = fn_run->next;
        free(fn_run->fn);
        free(fn_run);
        fn_run = fn_tmp;
    }
}

STA_OBJECT *sta_Find_Object(STA_OBJECT *object_head, char *mdsql){
    STA_OBJECT *object_run;
    STA_VALUE *value_run;
    DICT_ARRAY *da_run, *da_cmp;

    object_run = object_head;
    for(;object_run;object_run = object_run->next){
        value_run = object_run->sv;
        if(NULL == value_run) continue;
        da_run = value_run->sta_base_link->next->da;
        da_cmp = dict_find_array(da_run, "md5_sql");
        if(NULL == da_cmp) continue;
        if(strcmp(da_cmp->value, mdsql) == 0 ) return object_run;
    }
    return NULL;
}

STA_OBJECT *object_init(void){
    STA_OBJECT *object_head;

    object_head = (STA_OBJECT *)calloc(1, sizeof(STA_OBJECT));
    object_head->sv = NULL;
    object_head->next = NULL;
    
    return object_head;
}

unsigned int object_length(STA_OBJECT *object_head){
    unsigned int i;
    STA_OBJECT *object_run;
    object_run = object_head;

    for(;object_run;object_run=object_run->next)i++;
    
    return i;
}

void object_free_all(STA_OBJECT *object_head){
    STA_OBJECT *object_run, *object_tmp;

    object_run = object_head;
    while(object_run != NULL){
        object_tmp = object_run->next;
        object_free(object_run);
        object_run = object_tmp;
    }
}

void object_free(STA_OBJECT *object_link){
    STA_OBJECT *object_run;
    STA_VALUE *value_run;
   
    if(object_link != NULL){ 
        object_run = object_link;
        value_run = object_run->sv;
        dict_free(value_run->sta_base_link);
        dict_free(value_run->sta_explain_link);
        free(value_run);
        free(object_run);
    }
}

void object_reject_end(STA_OBJECT *object_head){
    unsigned int i;
    STA_OBJECT *object_run, *object_tmp;

    object_run = object_head;
    i = 0;
    while(object_run){
        if(i >= 50){
            object_tmp->next = object_run->next;
            object_free(object_run);
            object_run = object_tmp->next; 
            i--;
        }else{
            object_tmp = object_run;

            object_run = object_run->next;
        }
        i++;
    }
}

/* add sql and run_time but not run explian */
void sta_add_base_link(char *sql, double took){
    STA_OBJECT *sta_object_run;
    /*STA_VALUE *sta_value_run;*/
    FieldName *fn_heads;
    DICT_LINK *dict_link_head, *dict_base_head;
    DICT_ARRAY *dict_da_run;
    unsigned int num_fields=5,  hits, i;
    char *md_sql_run=NULL;
    char *row[num_fields];
    
    to_md5(sql, &md_sql_run);
    pthread_mutex_lock(&sta_lock);
   
    object_reject_end(status_object_head);

    sta_object_run = sta_Find_Object(status_object_head, md_sql_run); 
   
    if(sta_object_run == NULL){
        
        /*sta_value_run = status_value_init();*/
        memset(row, '\0', sizeof(row));
        row[0] = strdup(sql);
        row[1] = strdup(md_sql_run);
        row[2] = (char *)calloc(100, sizeof(char));
        snprintf(row[2], 99, "%f", took);
        row[3] = strdup("0");
        row[4] = strdup("1");

        dict_base_head = dict_init();

        fn_heads = status_fn_head;
        dict_base_head->da = dict_add(fn_heads, row, num_fields);

        sta_object_run = object_init();
        sta_object_run->sv = status_value_init();
        dict_link_head = dict_init();
        dict_link_head->next = dict_base_head;
        sta_object_run->sv->sta_base_link = dict_link_head;
        sta_object_run->sv->sta_explain_link = NULL;

        sta_object_run->next = status_object_head;
        status_object_head = sta_object_run; 
        for(i=0;i<num_fields;i++){
            free(row[i]);
        }
    }else{
        dict_link_head = sta_object_run->sv->sta_base_link;
        dict_da_run = dict_find_array(dict_link_head->next->da, "query_took");
        if(dict_da_run != NULL){
            if(took > atoi(dict_da_run->value)){
                free(dict_da_run->value);
                dict_da_run->value = NULL;
                dict_da_run->value = (char *)calloc(100, sizeof(char));
                snprintf(dict_da_run->value, 99, "%f", took);
            }
        }

        dict_da_run = dict_find_array(dict_link_head->next->da, "hits");
        if(dict_da_run != NULL){
            hits = atoi(dict_da_run->value); 
            free(dict_da_run->value);
            dict_da_run->value = NULL;
            dict_da_run->value = (char *)calloc(100, sizeof(char));
            snprintf(dict_da_run->value, 99, "%d", ++hits);
        }
    }
    pthread_mutex_unlock(&sta_lock);

    free(md_sql_run);
}

char *sta_get_link(void){
    STA_OBJECT *sta_object_run;
    STA_VALUE *sta_value_run;
    DICT_ARRAY *dict_array_run;
    DICT_LINK *dict_link_run;
	SQL_CONN *sm_conn;
    char *explain_sql, *json_res;
    unsigned int len;
    json_t *base_link_json, *explain_link_json, *jroot, *svinfo;

    sta_object_run = NULL;
    pthread_mutex_lock(&sta_lock);
    sta_object_run = status_object_head;
    jroot = json_new_array();

    for(; sta_object_run; sta_object_run=sta_object_run->next){
        sta_value_run = sta_object_run->sv;
        if(sta_value_run->sta_explain_link == NULL){	
            sm_conn = connect_sql();

            if(sm_conn == NULL) return NULL;
            dict_array_run = dict_find_array(sta_value_run->sta_base_link->next->da, "sql");
            if(NULL == dict_array_run) continue;
            len = strlen(dict_array_run->value);
            explain_sql = (char *)malloc(len+20);
            sprintf(explain_sql, "EXPLAIN %s", dict_array_run->value);
            dict_link_run = get_mysql(explain_sql, 0, sm_conn);
            free(explain_sql); 

            if(dict_link_run == NULL){
                dict_array_run = dict_find_array(sta_value_run->sta_base_link->next->da, "error_num");

                free(dict_array_run->value);
                dict_array_run->value = NULL;
                dict_array_run->value = strdup("1");
                explain_link_json = NULL;
            }else{
                sta_value_run->sta_explain_link = dict_link_run;

            }

        }
        if(NULL != sta_value_run->sta_explain_link)
            explain_link_json = dict_link_to_json_t(sta_value_run->sta_explain_link);  
        base_link_json = dict_link_to_json_t(sta_value_run->sta_base_link);
        
        svinfo = json_new_array();
        json_insert_child(svinfo, base_link_json);
        json_insert_child(svinfo, explain_link_json);

        json_insert_child(jroot, svinfo);
    }
     
    pthread_mutex_unlock(&sta_lock); 

    json_res = Json_to_String(jroot); 
    Json_Free_Root(jroot);
    return json_res;
}

int to_md5(unsigned char *source, char **target){
    unsigned char md[16];
    int i;
    char tmp[3]={'\0'},buf[33]={'\0'};
    MD5(source,strlen(source),md);
    for (i = 0; i < 16; i++){
        sprintf(tmp,"%2.2x",md[i]);
        strcat(buf,tmp);
    }   
    *target = strdup(buf);
    return 0;
}

/* vim: set ts=4 sw=4: */

